home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / util / misc / VMM_src.lha / VMM / fault.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-16  |  25.5 KB  |  970 lines

  1. #include <exec/types.h>
  2. #include "defs.h"
  3.  
  4. static char rcsid [] = "$Id: fault.c,v 3.6 95/12/16 18:36:51 Martin_Apel Exp $";
  5.  
  6. PRIVATE int PagesWaiting = 0;
  7.  
  8. /*******************************************************************/
  9.  
  10. void AddFree (struct TrapStruct *ThisFault)
  11.  
  12. {
  13. Forbid ();
  14. AddTail (&Free, (struct Node*) ThisFault);
  15. Permit ();
  16. }
  17.  
  18. /*******************************************************************/
  19.  
  20. void AddPageReq (struct TrapStruct *ThisFault)
  21.  
  22. {
  23. Forbid ();
  24. AddTail (&PageReq, (struct Node*) ThisFault);
  25. Permit ();
  26. }
  27.  
  28. /*******************************************************************/
  29.  
  30. PRIVATE void InformTask (struct TrapStruct *ThisFault)
  31.  
  32. {
  33. /* The page is back in memory. Signal the faulting task.
  34.  */
  35.  
  36. PageFaultsInProgress--;
  37. switch ((ULONG)ThisFault->FaultTask)
  38.   {
  39.   case REDUCE_TASK:  
  40.        /* The pagehandler is trying to reduce the paging memory.
  41.         * Check if it's enough, otherwise free another frame.
  42.         */
  43.        PRINT_DEB ("InformTask: Reduce", 0L);
  44.        if ((NumPageFrames * PAGESIZE > CurrentConfig.MaxMem) && 
  45.            (ThisFault->FaultAddress != NULL))
  46.          {
  47.          /* Do it again */
  48.          ThisFault->FaultAddress = NULL;
  49.          AddPageReq (ThisFault);
  50.          SetSignal (1L << PageFaultSignal, 1L << PageFaultSignal);
  51.          }
  52.        else
  53.          {
  54.          PRINT_DEB ("Finished reducing memory usage", 0L);
  55.          AddFree (ThisFault);
  56.          LowMem--;
  57.          }
  58.        break;  
  59.  
  60.   /*********************************/
  61.   case LOCK_TASK:
  62.        PRINT_DEB ("InformTask: Lock", 0L);
  63.        if (ThisFault->PageDescrAddr == NULL)
  64.          {
  65.          /* Just fetched the table. Do it again */
  66.          AddPageReq (ThisFault);
  67.          SetSignal (1L << PageFaultSignal, 1L << PageFaultSignal);
  68.          }
  69.        else
  70.          {
  71.          ThisPageLocked = (NumLocked + NumTables + 5 <= NumPageFrames) ||
  72.                           AddFrame (0L);
  73.  
  74.          if (ThisPageLocked)
  75.            {
  76.            NumLocked++;
  77.            Forbid ();
  78.            *(ThisFault->PageDescrAddr) |= LOCKED;
  79.            (*PFlushP) (ThisFault->FaultAddress);
  80.            Permit ();
  81.            }
  82.          else
  83.            PRINT_DEB ("Couldn't lock page. NumLocked = %ld", NumLocked);
  84.  
  85.          AddFree (ThisFault);
  86.          Signal ((struct Task*)VM_ManagerProcess, 1L << LockAckSignal);
  87.          }
  88.        break;
  89.  
  90.   /*********************************/
  91.   default:
  92. /*     PRINT_DEB ("Signalling waiting task %lx", (ULONG)ThisFault->FaultTask); */
  93.        CHECK_CONSISTENCY;
  94.        Signal (ThisFault->FaultTask, 1L << ThisFault->WakeupSignal);
  95.   }
  96. }
  97. /***********************************************************************/
  98.  
  99. void CheckWaitingFaults (void)
  100.  
  101. {
  102. struct TrapStruct *ThisFault,
  103.                   *Successor;
  104.  
  105. if (PagesWaiting == 0)
  106.   return;
  107.  
  108. /* Because ThisFault might be removed at the end of the loop,
  109.  * its successor is stored at the start of each looping
  110.  */
  111.  
  112. PRINT_DEB ("Checking for waiting pages", 0L);
  113.  
  114. for (ThisFault = (struct TrapStruct*)InTransit.lh_Head,
  115.      Successor = (struct TrapStruct*)ThisFault->TS_Node.mln_Succ;
  116.      ThisFault->TS_Node.mln_Succ != NULL;
  117.      ThisFault = Successor,
  118.      Successor = (struct TrapStruct*)ThisFault->TS_Node.mln_Succ)
  119.   {
  120.   if (((ThisFault->PageDescrAddr == NULL) &&        /* Table has come in */
  121.        (TABLE_RESIDENT_P (*(ThisFault->TableDescrAddr))))
  122.                           ||
  123.       ((ThisFault->PageDescrAddr != NULL) &&
  124.         PAGE_RESIDENT_P (*(ThisFault->PageDescrAddr))))  /* Page has come in */
  125.     {
  126.     PRINT_DEB ("Signalling waiting task", 0L);
  127.     Remove ((struct Node*)ThisFault);
  128.     PagesWaiting--;
  129.     InformTask (ThisFault);
  130.     }
  131.   }
  132. }
  133.  
  134. /***********************************************************************/
  135.  
  136. PRIVATE void MakePageResident (struct TrapStruct *ThisFault)
  137.  
  138. {
  139. struct FrameDescr *NewPage;
  140.  
  141. NewPage = ThisFault->FD;
  142. NewPage->PageType = PT_PAGE;
  143. NewPage->PageDescr = ThisFault->PageDescrAddr;
  144. NewPage->LogAddr = PAGEADDR(ThisFault->FaultAddress);
  145. NewPage->PageNumOnDisk = PGNUM_FROM_DESCR (*(ThisFault->PageDescrAddr));
  146. NewPage->Modified = FALSE;
  147.  
  148. Forbid ();
  149. *(ThisFault->PageDescrAddr) = ThisFault->PhysAddr | CACHE_MODE | PAGE_RESIDENT |
  150.            ((ThisFault->FaultTask == (struct Task*)LOCK_TASK) ? LOCKED : 0);
  151. (*PFlushP) (ThisFault->FaultAddress);
  152. (*FlushVirt) (NewPage->LogAddr);
  153. (*CPushP) (NewPage->PhysAddr);
  154. Permit ();
  155.  
  156. #ifdef NEW_PRA
  157. ReuseLate (ThisFault->FD);
  158. #else
  159. AddTail (&FrameList, (struct Node*)ThisFault->FD);
  160. ThisFault->FD->InFrameList = TRUE;
  161. #endif
  162. }
  163.  
  164. /*****************************************************************/
  165.  
  166. PRIVATE void MakeTableResident (struct TrapStruct *ThisFault)
  167.  
  168. {
  169. struct FrameDescr *NewTable;
  170. ULONG *TableStart;
  171. int i;
  172. #ifdef DEBUG
  173. ULONG *cur_descr;
  174. #endif
  175.  
  176. PRINT_DEB ("MakeTableResident: for address %lx", ThisFault->FaultAddress);
  177.  
  178. NewTable = ThisFault->FD;
  179. NewTable->PageType = PT_TABLE;
  180. NewTable->LogTableStart = ALIGN_DOWN (ThisFault->FaultAddress,
  181.                                       PAGESIZE * PAGESIZE / sizeof (ULONG));
  182. NewTable->PageNumOnDisk = PGNUM_FROM_DESCR (*(ThisFault->TableDescrAddr));
  183. PRINT_DEB ("MakeTableResident: PageNumOnDisk = %lx", NewTable->PageNumOnDisk);
  184. NewTable->Modified = FALSE;
  185.  
  186. /* One Page of page descriptors contains 16 page tables. So the
  187.  * pointers in the pointer table for those 16 page tables have to be
  188.  * marked as valid
  189.  */
  190.  
  191. #ifdef DEBUG
  192. cur_descr = (ULONG*)ThisFault->PhysAddr;
  193. for (i = 0; i < PAGESIZE / sizeof (ULONG); i++)
  194.   {
  195.   if (STATE_FROM_DESCR (*cur_descr++) == COMING_IN)
  196.     {
  197.     PRINT_DEB ("ERROR: Reading table with incoming pages", 0L);
  198.     ColdReboot ();
  199.     break;
  200.     }
  201.   }
  202. #endif
  203.  
  204. TableStart = (ULONG*)ALIGN_DOWN (*(RootTable + ROOTINDEX (ThisFault->FaultAddress)),
  205.                                  POINTERTABALIGN);
  206. TableStart += ALIGN_DOWN (POINTERINDEX (ThisFault->FaultAddress),
  207.                           PAGESIZE / sizeof (ULONG) / PAGES_PER_TABLE);
  208.  
  209. MarkPage ((ULONG)TableStart, NONCACHEABLE);
  210.  
  211. PRINT_DEB ("TableStart = %lx", (ULONG)TableStart);
  212.  
  213. Forbid ();
  214. for (i = 0; i < PAGESIZE / sizeof (ULONG) / PAGES_PER_TABLE; i++)
  215.   {
  216.   *(TableStart + i) =
  217.     (ThisFault->PhysAddr + i * PAGES_PER_TABLE * sizeof (ULONG)) | TABLE_RESIDENT;
  218.   }
  219.  
  220. (*PFlushA)();
  221. Permit ();
  222. #ifdef NEW_PRA
  223. ReuseLate (ThisFault->FD);
  224. #else
  225. AddTail (&FrameList, (struct Node*)ThisFault->FD);
  226. ThisFault->FD->InFrameList = TRUE;
  227. #endif
  228. NumTables++;
  229. }
  230.  
  231.  
  232. /*****************************************************************/
  233.  
  234. PRIVATE void MakePageInvalid (struct FrameDescr *fd)
  235.  
  236. {
  237. #ifdef DEBUG
  238. if (!fd->InFrameList)
  239.   {
  240.   PRINT_DEB ("MakePageInvalid: Frame not in frame list", 0L);
  241.   ColdReboot ();
  242.   }
  243. #endif
  244.  
  245. #ifdef NEW_PRA
  246. RemoveFromAvail (fd);
  247. #else
  248. Remove ((struct Node*)fd);
  249. fd->InFrameList = FALSE;
  250. #endif
  251.  
  252. Forbid ();
  253. *(fd->PageDescr) = BUILD_DESCR (fd->PageNumOnDisk, PAGED_OUT, PT_PAGE);
  254. (*PFlushP) (fd->LogAddr);
  255. (*CPushP) (fd->PhysAddr);
  256. (*FlushVirt) (fd->LogAddr);
  257. Permit ();
  258. }
  259.  
  260. /*****************************************************************/
  261.  
  262. PRIVATE void MakeTableInvalid (struct FrameDescr *fd)
  263.  
  264. {
  265. ULONG *TableStart;
  266. int i;
  267.  
  268. PRINT_DEB ("MakeTableInvalid: PageNumOnDisk = %lx", fd->PageNumOnDisk);
  269.  
  270. #ifdef DEBUG
  271. if (!fd->InFrameList)
  272.   {
  273.   PRINT_DEB ("MakeTableInvalid: Frame not in frame list", 0L);
  274.   ColdReboot ();
  275.   }
  276. #endif
  277.  
  278. #ifdef NEW_PRA
  279. RemoveFromAvail (fd);
  280. #else
  281. Remove ((struct Node*)fd);
  282. fd->InFrameList = FALSE;
  283. #endif
  284.  
  285. TableStart = (ULONG*)ALIGN_DOWN (*(RootTable + ROOTINDEX (fd->LogTableStart)),
  286.                                  POINTERTABALIGN);
  287. TableStart += POINTERINDEX (fd->LogTableStart);
  288.  
  289. Forbid ();
  290. for (i = 0; i < PAGESIZE / sizeof (ULONG) / PAGES_PER_TABLE; i++)
  291.   {
  292.   *(TableStart + i) = BUILD_DESCR (fd->PageNumOnDisk, PAGED_OUT, PT_TABLE);
  293.   }
  294.  
  295. (*PFlushA) ();
  296. Permit ();
  297. MarkPage ((ULONG)TableStart, CACHEABLE);
  298. NumTables--;
  299. }
  300.  
  301. /*****************************************************************/
  302.  
  303. PRIVATE void InstallNewTable (struct TrapStruct *ThisFault)
  304.  
  305. {
  306. ULONG *TableStart;
  307. int i;
  308.  
  309. PRINT_DEB ("InstallNewTable called", 0L);
  310.  
  311. /* Make all page descriptors in this page invalid */
  312. TableStart = (ULONG*)ThisFault->PhysAddr;    /* Start of page table */
  313. for (i = 0; i < PAGESIZE / sizeof (ULONG); i++)
  314.   {
  315.   *(TableStart + i) = BUILD_DESCR (LOCUNUSED, PAGED_OUT, PT_PAGE);
  316.   }
  317.  
  318. MakeTableResident (ThisFault);
  319. }
  320.  
  321. /*****************************************************************/
  322.  
  323. #ifndef NEW_PRA
  324. PRIVATE BOOL TablePagingAllowed (struct FrameDescr *table_frame)
  325.  
  326. {
  327. ULONG *cur_descr;
  328. int i;
  329.  
  330. cur_descr = (ULONG*) table_frame->PhysAddr;
  331. for (i = 0; i < PAGESIZE / sizeof (ULONG); i++, cur_descr++)
  332.   {
  333.   if (PAGE_RESIDENT_P (*cur_descr) || (STATE_FROM_DESCR (*cur_descr) == COMING_IN))
  334.     return (FALSE);
  335.   }
  336. return (TRUE);
  337. }
  338. #endif
  339.  
  340. /*****************************************************************/
  341.  
  342. #define PAGE_NOT_IN_USE(fd) (((fd)->PageType == PT_PAGE) &&\
  343.                              ((!PAGE_RESIDENT_P(*((fd)->PageDescr))) &&\
  344.                               !MODIFIED_P(*fd)))
  345.  
  346. PRIVATE short Evict (struct TrapStruct *ThisFault)
  347.  
  348. {
  349. /* A page fault has occurred. Find a page to put on disk.
  350.  * Writes the physical address of the evicted page frame into
  351.  * ThisFault->PhysAddr.
  352.  * This routine returns after sending the write request to the handler
  353.  * The chosen frame is removed from FrameList until it is used again
  354.  */
  355.  
  356. struct FrameDescr *chosen,
  357.                   *cur_frame;
  358. BOOL found = FALSE;
  359. static ULONG AvailableForFrames = 100000L;
  360.  
  361. /* Add another frame only when all of the following conditions apply:
  362.  *   Dynamic policy
  363.  *   Not currently evicting page-frames to make room for some physical request
  364.  *   First frame is not empty
  365.  *   First frame is not unused and unmodified (probably generated by a 
  366.  *   FreeMem which marked this frame in this way.
  367.  */
  368. if ((NumPageFrames * PAGESIZE < CurrentConfig.MaxMem) && (!LowMem) &&
  369.    (((struct FrameDescr*)(FrameList.lh_Head))->PageType != PT_EMPTY) &&
  370.    !PAGE_NOT_IN_USE(((struct FrameDescr*)(FrameList.lh_Head))))
  371.  
  372.   {
  373.   /* This way AddFrame will only retry allocation of a frame if some
  374.    * other memory has been freed in the meantime (since the last
  375.    * allocation failed).
  376.    */
  377.   if (AddFrame (AvailableForFrames))
  378.     AvailableForFrames = 1L;
  379.   else
  380.     AvailableForFrames = DoOrigAvailMem (CurrentConfig.MemFlags);
  381.   }
  382.  
  383. #ifdef NEW_PRA
  384. chosen = FindRemoveablePage ();
  385. #else
  386.  
  387. do
  388.   {
  389.   cur_frame = (struct FrameDescr*)RemHead (&FrameList);
  390. #ifdef SCHED_STAT
  391.   FramesExamined++;
  392. #endif
  393. #ifdef DEBUG
  394.   if (cur_frame == NULL)
  395.     {
  396.     PRINT_DEB ("Internal error: FrameList empty", 0L);
  397.     ColdReboot ();
  398.     }
  399. #endif
  400.   AddTail (&FrameList, (struct Node*)cur_frame);
  401.  
  402.   if (cur_frame->PageType == PT_EMPTY)
  403.     {
  404.     ThisFault->PhysAddr = (ULONG)cur_frame->PhysAddr;
  405.     ThisFault->FD = cur_frame;
  406.     Remove ((struct Node*)cur_frame);
  407.     cur_frame->InFrameList = FALSE;
  408.     return (READY);
  409.     }
  410.  
  411.   if ((cur_frame->PageType == PT_PAGE) && LOCKED_P (*(cur_frame->PageDescr)))
  412.     ;
  413.   else if ((cur_frame->PageType == PT_PAGE) &&
  414.            (USED_P (*cur_frame->PageDescr)))
  415.     {
  416.     Forbid ();
  417.     if (MODIFIED_P (*cur_frame))
  418.       cur_frame->Modified = TRUE;
  419.     *cur_frame->PageDescr &= ~(USED | MODIFIED);
  420.     (*PFlushP) (cur_frame->LogAddr);
  421.     Permit ();
  422.     }
  423.   else if (cur_frame->PageType == PT_TABLE)
  424.     {
  425.     /* Check if any of the descriptors in this page are still valid.
  426.      * Otherwise this page table can be written to disk.
  427.      */
  428.     if (TablePagingAllowed (cur_frame))
  429.       found = TRUE;
  430.     }
  431.   else
  432.     found = TRUE;             /* Found an unused page */
  433.   }
  434. while (!found);
  435.  
  436. chosen = cur_frame;
  437. #endif
  438.  
  439. /* Empty pages cannot occur here */
  440. ThisFault->PhysAddr = chosen->PhysAddr;
  441.  
  442. ThisFault->FD = chosen;
  443.  
  444. #ifdef DEBUG
  445.  
  446. if (chosen->PageType == PT_PAGE)
  447.   /* PRINT_DEB ("Evicting page frame for log. address %lx", chosen->LogAddr) */;
  448. else if (chosen->PageType == PT_TABLE)
  449.   PRINT_DEB ("Evicting table frame for address range %lx", chosen->LogTableStart);
  450. else
  451.   {
  452.   PRINT_DEB ("Internal error: Empty page in Evict. Type %ld", (LONG)chosen->PageType);
  453.   ColdReboot ();
  454.   }
  455. #endif
  456. /* PRINT_DEB ("Physical address is %lx", ThisFault->PhysAddr); */
  457.  
  458. Forbid ();          /* Have to forbid here, otherwise this page could
  459.                      * be modified after it has been tested for modification.
  460.                      */
  461. if ((chosen->PageType == PT_PAGE) && !MODIFIED_P (*chosen))
  462.   {
  463.   /* Don't need to write this one back.
  464.    * Mark this address as invalid
  465.    */
  466.   MakePageInvalid (chosen);
  467.   Permit ();
  468.   return (READY);
  469.   }
  470. else
  471.   {
  472.   /* Write out modified page first */
  473.  
  474.   if (chosen->PageNumOnDisk != LOCUNUSED)
  475.     FreePageOnDisk (chosen->PageNumOnDisk);
  476.   chosen->PageNumOnDisk = AllocPageOnDisk ();
  477.  
  478.   if (chosen->PageType == PT_TABLE)
  479.     MakeTableInvalid (chosen);
  480.   else
  481.     MakePageInvalid (chosen);
  482.  
  483.   Permit ();
  484.   if (chosen->PageType == PT_TABLE)
  485.     {
  486.     PRINT_DEB ("PhysTableStart is %lx", (ULONG)chosen->PhysAddr);
  487.     PRINT_DEB ("LogTableStart is %lx", chosen->LogTableStart);
  488.     PRINT_DEB ("PageNumOnDisk = %lx", (ULONG)chosen->PageNumOnDisk);
  489.     (*PFlushP) (ThisFault->FaultAddress);
  490.     }
  491.   return (WritePage (chosen->PageNumOnDisk, ThisFault));
  492.   }
  493. }
  494.  
  495. /**********************************************************************/
  496.  
  497. PRIVATE short GetNewPage (struct TrapStruct *ThisFault)
  498.  
  499. {
  500. /* There's a place free at physical address ThisFault->PhysAddr.
  501.  * Either read the needed page from disk or if this is the first reference
  502.  * install a new one
  503.  */
  504.  
  505. if (PGNUM_FROM_DESCR (*(ThisFault->PageDescrAddr)) == LOCUNUSED)
  506.   {
  507.   /* PRINT_DEB ("Installing new page", 0L); */
  508.   MakePageResident (ThisFault);
  509.   return (READY);
  510.   }
  511. else
  512.   {
  513.   if (ReadPage (PGNUM_FROM_DESCR (*(ThisFault->PageDescrAddr)), ThisFault) == READY)
  514.     {
  515.     MakePageResident (ThisFault);
  516.     return (READY);
  517.     }
  518.   return (IN_PROGRESS);
  519.   }
  520. }
  521.  
  522. /**********************************************************************/
  523.  
  524. PRIVATE short GetNewTable (struct TrapStruct *ThisFault)
  525.  
  526. {
  527. if (PGNUM_FROM_DESCR (*(ThisFault->TableDescrAddr)) == LOCUNUSED)
  528.   {
  529.   PRINT_DEB ("Installing new page table", 0L);
  530.   InstallNewTable (ThisFault);
  531.   return (READY);
  532.   }
  533. else
  534.   {
  535.   if (ReadPage (PGNUM_FROM_DESCR (*(ThisFault->TableDescrAddr)), ThisFault) == READY)
  536.     {
  537.     MakeTableResident (ThisFault);
  538.     return (READY);
  539.     }
  540.   return (IN_PROGRESS);
  541.   }
  542. }
  543.  
  544. /***********************************************************************/
  545.  
  546. PRIVATE void HandleMissingPage (struct TrapStruct *ThisFault)
  547.  
  548. {
  549. if (PAGE_RESIDENT_P (*(ThisFault->PageDescrAddr)))
  550.   {
  551.   /* Page was just requested by another task and has already come in */
  552.   PRINT_DEB ("Faulted page has already come in", 0L);
  553.   InformTask (ThisFault);
  554.   }
  555. else if (STATE_FROM_DESCR (*(ThisFault->PageDescrAddr)) == COMING_IN)
  556.   {
  557.   /* Page was just requested by another task and is in transit */
  558.   AddTail (&InTransit, (struct Node*)ThisFault);
  559.   PagesWaiting++;
  560.   PRINT_DEB ("Putting fault to sleep", 0L);
  561.   PRINT_DEB ("TableDescr is at %lx", (ULONG)ThisFault->TableDescrAddr);
  562.   PRINT_DEB ("TableDescr contains %lx", *(ThisFault->TableDescrAddr));
  563.   PRINT_DEB ("PageDescr is at %lx", (ULONG)ThisFault->PageDescrAddr);
  564.   PRINT_DEB ("PageDescr contains %lx", *(ThisFault->PageDescrAddr));
  565.   }
  566. else
  567.   {
  568.   /* Start handling */
  569.   *(ThisFault->PageDescrAddr) =
  570.      BUILD_DESCR (PGNUM_FROM_DESCR (*(ThisFault->PageDescrAddr)),
  571.                   COMING_IN, TYPE_FROM_DESCR (*(ThisFault->PageDescrAddr)));
  572.  
  573.   (*PFlushP) (ThisFault->FaultAddress);
  574.  
  575.   if (Evict (ThisFault) == READY)
  576.     {
  577.     if (GetNewPage (ThisFault) == READY)
  578.       {
  579.       InformTask (ThisFault);
  580.       CheckWaitingFaults ();
  581.       }
  582.     }
  583.   }
  584. }
  585.  
  586. /***********************************************************************/
  587.  
  588. PRIVATE void HandleMissingTable (struct TrapStruct *ThisFault)
  589.  
  590. {
  591. PRINT_DEB ("Table missing", 0L);
  592.  
  593. if (TABLE_RESIDENT_P (*(ThisFault->TableDescrAddr)))
  594.   {
  595.   /* Table was requested by another task and has already come in */
  596.   PRINT_DEB ("Faulted table has already come in", 0L);
  597.   InformTask (ThisFault);
  598.   }
  599. else if (STATE_FROM_DESCR (*(ThisFault->TableDescrAddr)) == COMING_IN)
  600.   {
  601.   PRINT_DEB ("Requested table is coming in", 0L);
  602.   AddTail (&InTransit, (struct Node*)ThisFault);
  603.   PagesWaiting++;
  604.   }
  605. else
  606.   {
  607.   /* Get this table */
  608.   *(ThisFault->TableDescrAddr) =
  609.      BUILD_DESCR (PGNUM_FROM_DESCR (*(ThisFault->TableDescrAddr)),
  610.                   COMING_IN, TYPE_FROM_DESCR (*(ThisFault->TableDescrAddr)));
  611.  
  612.   (*PFlushA) ();
  613.  
  614.   if (Evict (ThisFault) == READY)
  615.     {
  616.     if (GetNewTable (ThisFault) == READY)
  617.       {
  618.       InformTask (ThisFault);
  619.       CheckWaitingFaults ();
  620.       }
  621.     }
  622.   }
  623. }
  624.  
  625. /***********************************************************************/
  626.  
  627. PRIVATE struct FrameDescr *FindFrame (ULONG RequiredFlags)
  628.  
  629. {
  630. /* Finds an evictable frame with the desired memory flags and returns it
  631.  * In order to free the frames the reverse way they were allocated,
  632.  * the following is done:
  633.  * One frame to be evicted is chosen in the standard way.
  634.  * A frame from the front of the FrameOrderList is chosen, which
  635.  * is not currently involved in paging (PageDescr != INVALID).
  636.  * This frame is copied to the evicted frame. The memory of the chosen
  637.  * frame is freed then.
  638.  */
  639.  
  640. struct FrameDescr *tmp_fd;
  641. struct MinNode    *tmp_alloc_node;
  642. BOOL found = FALSE;
  643.  
  644. tmp_alloc_node = (struct MinNode*)FrameAllocList.lh_Head;
  645.  
  646. while (!found)
  647.   {
  648.   tmp_fd = (struct FrameDescr*)(tmp_alloc_node - 1);
  649.   if (tmp_fd->InFrameList)
  650.     {
  651.     switch (tmp_fd->PageType)
  652.       {
  653.       case PT_PAGE : if (!LOCKED_P (*(tmp_fd->PageDescr)))
  654.                        found = TRUE;
  655.                      break;
  656.       case PT_TABLE: if (TablePagingAllowed (tmp_fd))
  657.                        found = TRUE;
  658.                      break;
  659.       case PT_EMPTY: found = TRUE;
  660.                      break;
  661.       }
  662.     }
  663.  
  664.   /* Makes use of the evaluation order of boolean expressions */
  665.   if (!found || ((RequiredFlags & TypeOfMem ((APTR)tmp_fd->PhysAddr))
  666.                  != RequiredFlags))
  667.     {
  668.     found = FALSE;
  669.     tmp_alloc_node = tmp_alloc_node->mln_Succ;
  670.     if (tmp_alloc_node->mln_Succ == 0)
  671.       return (NULL);
  672.     }
  673.   }
  674.  
  675. return (tmp_fd);
  676. }
  677.  
  678. /***********************************************************************/
  679.  
  680. PRIVATE short RemFrameFinish (struct TrapStruct *ThisFault)
  681.  
  682. {
  683.  
  684. struct FrameDescr *rem_frame;           /* The frame to be removed */
  685. ULONG phys_addr;
  686. BOOL modified;
  687. ULONG DesiredFlags;
  688.  
  689. /* If more than 25 frames are requested, frames are not copied.
  690.  * Apparently more frames are needed so this will only waste
  691.  * time.
  692.  */
  693.  
  694. if ((LONG)ThisFault->RemFrameSize - 
  695.     (LONG)DoOrigAvailMem (ThisFault->RemFrameFlags | MEMF_PUBLIC) 
  696.     > 25 * PAGESIZE)
  697.   {
  698.   PRINT_DEB ("Needing a lot of frames. Not copying", 0L);
  699.   Remove ((struct Node*)&(ThisFault->FD->OrderNode));
  700.   FreeMem ((APTR)ThisFault->FD->PhysAddr, PAGESIZE);
  701.   FreeMem (ThisFault->FD, sizeof (struct FrameDescr));
  702.   ThisFault->FramesRemoved++;
  703.   ThisFault->RemFrameSize -= PAGESIZE;
  704.   NumPageFrames--;
  705.  
  706.   /* Try again */
  707.   Forbid ();
  708.   AddHead (&PageReq, (struct Node*) ThisFault);
  709.   Permit ();
  710.   SetSignal (1L << PageFaultSignal, 1L << PageFaultSignal);
  711.   PageFaultsInProgress--;
  712.   PRINT_DEB ("Retrying RemFrame", 0L);
  713.  
  714.   PRINT_DEB ("Page frames left: %ld", NumPageFrames);
  715.   return (IN_PROGRESS);
  716.   }
  717.  
  718. DesiredFlags = ThisFault->RemFrameFlags &
  719.                (MEMF_PUBLIC | MEMF_FAST | MEMF_CHIP);
  720.  
  721. /* If chip memory is not required explicitly, try to free a frame in
  722.  * fast memory. This way program code is run much faster.
  723.  */
  724. if (!(DesiredFlags & MEMF_CHIP))
  725.   {
  726.   if ((rem_frame = FindFrame (DesiredFlags | MEMF_FAST)) == NULL)
  727.     rem_frame = FindFrame (DesiredFlags);
  728.   }
  729. else
  730.   rem_frame = FindFrame (DesiredFlags);
  731.  
  732. if (rem_frame == NULL)
  733.   {
  734.   PRINT_DEB ("Didn't find frame with desired flags %lx", DesiredFlags);
  735.   ThisFault->FD->PageType = PT_EMPTY;
  736.   ThisFault->FD->Modified = FALSE;
  737.   ThisFault->FD->PageNumOnDisk = LOCUNUSED;
  738.   AddHead (&FrameList, (struct Node*)ThisFault->FD);
  739.   ThisFault->FD->InFrameList = TRUE;
  740.   return (READY);
  741.   }
  742.  
  743. phys_addr = rem_frame->PhysAddr;
  744. Forbid ();
  745. switch (rem_frame->PageType)
  746.   {
  747.   case PT_PAGE:
  748.     (*FlushVirt) (phys_addr);        /* == logical address here */
  749.     CopyMemQuick ((APTR)phys_addr,
  750.                   (APTR)ThisFault->PhysAddr, PAGESIZE);
  751.     modified = MODIFIED_P (*rem_frame);
  752.     MakePageInvalid (rem_frame);
  753.     ThisFault->FaultAddress = rem_frame->LogAddr;
  754.     ThisFault->PageDescrAddr = rem_frame->PageDescr;
  755.     MakePageResident (ThisFault);
  756.     ThisFault->FD->Modified = modified;
  757.     break;
  758.   case PT_TABLE:
  759.     PRINT_DEB ("RemFrameFinish: Removing table. Copying to %lx", ThisFault->PhysAddr);
  760.     (*FlushVirt) (phys_addr);        /* == logical address here */
  761.     CopyMemQuick ((APTR)phys_addr,
  762.                   (APTR)ThisFault->PhysAddr, PAGESIZE);
  763.     MakeTableInvalid (rem_frame);
  764.     ThisFault->FaultAddress = rem_frame->LogTableStart;
  765.     ThisFault->TableDescrAddr = (ULONG*)
  766.                ALIGN_DOWN (*(RootTable + ROOTINDEX (ThisFault->FaultAddress)),
  767.                            POINTERTABALIGN);
  768.     ThisFault->TableDescrAddr += POINTERINDEX (ThisFault->FaultAddress);
  769.     MakeTableResident (ThisFault);
  770.     break;
  771.   case PT_EMPTY:
  772.     PRINT_DEB ("RemFrameFinish: Removing empty page", 0L);
  773.     ThisFault->FD->PageType = PT_EMPTY;
  774.     ThisFault->FD->Modified = FALSE;
  775.     ThisFault->FD->PageNumOnDisk = LOCUNUSED;
  776. #ifdef DEBUG
  777.     if (!rem_frame->InFrameList)
  778.       {
  779.       PRINT_DEB ("RemFrameFinish: Removing frame not in frame list", 0L);
  780.       ColdReboot ();
  781.       }
  782. #endif
  783.     Remove ((struct Node*)rem_frame);
  784.     rem_frame->InFrameList = FALSE;
  785.     AddHead (&FrameList, (struct Node*)ThisFault->FD);
  786.     ThisFault->FD->InFrameList = TRUE;
  787.     break;
  788.   }
  789.  
  790. Permit ();
  791.  
  792. Remove ((struct Node*)&(rem_frame->OrderNode));
  793. FreeMem ((APTR)rem_frame->PhysAddr, PAGESIZE);
  794. FreeMem (rem_frame, sizeof (struct FrameDescr));
  795. ThisFault->FramesRemoved++;
  796. NumPageFrames--;
  797.  
  798. PRINT_DEB ("Page frames left: %ld", NumPageFrames);
  799. return (READY);
  800. }
  801.  
  802. /***********************************************************************/
  803.  
  804. PRIVATE void RemFrame (struct TrapStruct *ThisFault)
  805.  
  806. {
  807. PRINT_DEB ("RemFrame called with flags %lx", ThisFault->RemFrameFlags);
  808. PRINT_DEB ("                     size  %lx", ThisFault->RemFrameSize);
  809.  
  810. if (((CurrentConfig.PageDev == PD_FILE) && 
  811.      (ThisFault->FaultTask == (struct Task*)FileHandlerProcess)) ||
  812.      (NumPageFrames * PAGESIZE <= CurrentConfig.MinMem) || 
  813.      ((NumLocked + 3) >= NumPageFrames))
  814.   {
  815.   PRINT_DEB ("Not enough frames", 0L);
  816.   InformTask (ThisFault);
  817.   return;
  818.   }
  819.  
  820. if (Evict (ThisFault) == READY)
  821.   {
  822.   if (RemFrameFinish (ThisFault) == READY)
  823.     InformTask (ThisFault);
  824.   }
  825. }
  826.  
  827. /***********************************************************************/
  828.  
  829. void HandlePageFault (void)
  830.  
  831. {
  832. struct TrapStruct *ThisFault;
  833. ULONG *PageTable;
  834.  
  835. Forbid ();
  836. ThisFault = (struct TrapStruct*)RemHead (&PageReq);
  837. Permit ();
  838.  
  839. while (ThisFault != NULL)
  840.   {
  841.   /* PRINT_DEB ("FaultAddress is %08lx", ThisFault->FaultAddress); */
  842.   PageFaultsInProgress++;
  843.   CHECK_CONSISTENCY;
  844.  
  845.   if (ThisFault->FaultAddress == NULL)
  846.     RemFrame (ThisFault);          /* Free a frame */
  847.   else 
  848.     {
  849.     NumPageFaults++;
  850.  
  851.     ThisFault->TableDescrAddr = (ULONG*)
  852.                ALIGN_DOWN (*(RootTable + ROOTINDEX (ThisFault->FaultAddress)),
  853.                            POINTERTABALIGN);
  854.     ThisFault->TableDescrAddr += POINTERINDEX (ThisFault->FaultAddress);
  855.  
  856.     if (TABLE_RESIDENT_P (*(ThisFault->TableDescrAddr)))
  857.       {
  858.       PageTable = (ULONG*) ALIGN_DOWN (*(ThisFault->TableDescrAddr), PAGETABALIGN);
  859.       ThisFault->PageDescrAddr = PageTable + PAGEINDEX(ThisFault->FaultAddress);
  860.       HandleMissingPage (ThisFault);
  861.       }
  862.     else
  863.       {
  864.       ThisFault->PageDescrAddr = NULL;
  865.       HandleMissingTable (ThisFault);
  866.       }
  867.     }
  868.   Forbid ();
  869.   ThisFault = (struct TrapStruct*)RemHead (&PageReq);
  870.   Permit ();
  871.   }
  872. }
  873.  
  874. /*****************************************************************/
  875.  
  876. void ReadReturned (struct TrapStruct *ThisFault)
  877.  
  878. {
  879. /* PRINT_DEB ("Returned from reading", 0L); */
  880.  
  881. if (ThisFault->PageDescrAddr == NULL)
  882.   MakeTableResident (ThisFault);
  883. else
  884.   MakePageResident (ThisFault);
  885. InformTask (ThisFault);
  886. }
  887.  
  888. /*****************************************************************/
  889.  
  890. void WriteReturned (struct TrapStruct *ThisFault)
  891.  
  892. {
  893. short state;
  894.  
  895. /* PRINT_DEB ("Returned from writing", 0L); */
  896. if (ThisFault->FaultAddress == NULL)
  897.   state = RemFrameFinish (ThisFault);
  898. else if (ThisFault->PageDescrAddr == NULL)
  899.   state = GetNewTable (ThisFault);
  900. else
  901.   state = GetNewPage (ThisFault);
  902.  
  903. if (state == READY)
  904.   InformTask (ThisFault);
  905. }
  906.  
  907. /*****************************************************************/
  908.  
  909. BOOL AddFrame (ULONG priority)
  910.  
  911. /* This function allocates a pageframe and the accompanying frame
  912.  * descriptor. If it is successfully allocated, it is put into
  913.  * the FrameList. Otherwise everything will be freed and FALSE
  914.  * will be returned.
  915.  */
  916.  
  917. {
  918. char *frame;
  919. struct FrameDescr *FD;
  920.  
  921. /* PRINT_DEB ("AllocFrame called", 0L); */
  922.  
  923. if ((frame = AllocAligned (PAGESIZE, CurrentConfig.MemFlags | MEMF_REVERSE,
  924.                            PAGEALIGN, priority)) == NULL)
  925.   {
  926.   /* PRINT_DEB ("Couldn't allocate mem for page-frame", 0L); */
  927.   return (FALSE);
  928.   }
  929.  
  930. if ((FD = DoOrigAllocMem (sizeof (struct FrameDescr), MEMF_PUBLIC)) == NULL)
  931.   {
  932.   PRINT_DEB ("No mem for frame descriptor", 0L);
  933.   FreeMem (frame, PAGESIZE);
  934.   return (FALSE);
  935.   }
  936.  
  937. FD->PageType = PT_EMPTY;
  938. FD->Modified = FALSE;
  939. FD->PhysAddr = (ULONG)frame;
  940.  
  941. AddHead (&FrameList, (struct Node*)FD);
  942. FD->InFrameList = TRUE;
  943. AddHead (&FrameAllocList, (struct Node*)&(FD->OrderNode));
  944.  
  945. NumPageFrames++;
  946. return (TRUE);
  947. }
  948.  
  949. /***********************************************************************/
  950.  
  951. void RemAllFrames (void)
  952.  
  953. {
  954. struct FrameDescr *tmp_fd;
  955.  
  956. while ((tmp_fd = (struct FrameDescr*)RemHead (&FrameList)) != NULL)
  957.   {
  958.   Remove ((struct Node*)&(tmp_fd->OrderNode));
  959.  
  960.   /* The pages themselves are separately freed unless they are not marked
  961.    * as empty.
  962.    */
  963.   if (tmp_fd->PageType == PT_EMPTY)
  964.     FreeMem ((APTR)tmp_fd->PhysAddr, PAGESIZE);
  965.   FreeMem (tmp_fd, sizeof (struct FrameDescr));
  966.   }
  967.  
  968. NumPageFrames = 0;
  969. }
  970.